#include "SMSmonitor.h"
#include "mtalog.h"
#include <avkon.mbg>

#define KUidGlobalNote 270561816
#define KUidSelf 0xEEAD5B01

SMSMonitor* SMSMonitor::self = 0;

/**
 * Public interface for the Singleton pattern
 * @return - NONE
 * */
SMSMonitor* SMSMonitor::GetInstance()
{
	if(self == 0)
	{
		TRAPD(error, NewL());
		if(error != KErrNone)
			return 0;
	}
	return self;
}

/**
 * Symbian style constructor
 * @return - NONE
 * */
void SMSMonitor::NewL()
{
	self = new(ELeave)SMSMonitor();
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
}

/**
 * Second level constructor
 * @return - NONE
 * */
void SMSMonitor::ConstructL()
{
	iForegroundObserver = CForegroundObserver::NewL();
	CActiveScheduler::Add(this);
}

/**
 * Constructor
 * @return - NONE
 * */
SMSMonitor::SMSMonitor() : CActive(EPriorityNormal), iSession(0), iApplicationRunning(true), 
		iNoteDisplayed(false), iMsgReceived(false), iMsgSendingAttempted(false), iForegroundObserver(0)
{
}

/**
 * Destructor
 * @return - NONE
 * */
SMSMonitor::~SMSMonitor()
{
	Stop();
	if(iForegroundObserver)
	{
		delete iForegroundObserver;
		iForegroundObserver = 0;
	}
}

/**
 * This function starts the application
 * @return - NONE
 * */
void SMSMonitor::Start()
{
	/** We can check for a setting here and return if the application shouldn't start */
	TRAPD(err,(iSession = CMsvSession::OpenAsObserverL(*this)));
	iMtmRegistry = CClientMtmRegistry::NewL( *iSession ); /** Create an MTM Registry object. */
	CleanupStack::PushL(iMtmRegistry);
	/** Create an SMS Client MTM object */
	iSmsMtm = STATIC_CAST( CSmsClientMtm*, iMtmRegistry->NewMtmL( KUidMsgTypeSMS ) ); 
	iBaseMtm = iMtmRegistry->NewMtmL(KUidMsgTypeSMS);
	iMtmUiReg = CMtmUiRegistry::NewL(*iSession);
	CleanupStack::Pop(iMtmRegistry);

	iForegroundObserver->Start();
	RWsSession wsSession = CCoeEnv::Static()->WsSession();
	TApaTaskList* taskList = new TApaTaskList((wsSession));

	TUid uid;
	uid.iUid = KUidSelf;
	TApaTask task = taskList->FindApp(uid);
	if(task.Exists())
	{
		task.SendToBackground();
		iForegroundObserver->SimulateKey();
		if(IsUnreadItem()) /** After say reboot, if still some messages are unread */
		{
			ShowGlobalNoteL(true);
		}
	}
	iApplicationRunning = true;
}

/**
 * This function stops the application
 * @return - NONE 
 * */
void SMSMonitor::Stop()
{
	if(iMtmRegistry)
	{
		delete iMtmRegistry;
		iMtmRegistry = NULL;
	}
	if(iSmsMtm)
	{
		delete iSmsMtm;
		iSmsMtm = NULL;
	}
	if(iMtmUiReg)
	{
		delete iMtmUiReg;
		iMtmUiReg = NULL;
	}
	if(iSession)
	{
		iSession->RemoveObserver(*this);
		delete iSession;
		iSession = NULL;
	}
	iApplicationRunning = false;
	iForegroundObserver->Stop();
}

/**
 * This function handles the message server notifications
 * @return - NONE
 * */
void SMSMonitor::HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* /*aArg3*/)
{
	switch (aEvent)
	{
	case EMsvEntriesCreated:
	{
		//LOGTXT("new entry created.");
		if(!iApplicationRunning)
			return;

		//LOGTXT("application is running");
		TMsvId* entryId = static_cast<TMsvId*>(aArg2);

		CMsvEntrySelection* entries = static_cast<CMsvEntrySelection*>(aArg1);
		if(entries)
		{
			//LOGTXT("inside entries if...");
			CMsvEntry* entry = 0;

			for(TInt index = 0; index < entries->Count(); index++)
			{
				//LOGARG("index...%d",index);
				entry = iSession->GetEntryL(entries->At(index));
				entry->OwningService();
				CleanupStack::PushL(entry);

				if(entry->Entry().iMtm == KUidMsgTypeSMS)// Incoming SMS
				{
					//LOGTXT("id type SMS");
					if ( *entryId == KMsvGlobalInBoxIndexEntryId )
					{
						if(iMsgSendingAttempted)
						{
							iMsgSendingAttempted = false;
							//LOGTXT("DELIVERY REPORT....SKIP IT");
							break;
						}
						
						iMessageId = entry->EntryId();
						iPhoneNumber.Zero();
						iPhoneNumber.Append(entry->Entry().iDetails);
						User::After(1000000);
						iMsgReceived = true;
						//LOGTXT("iMsgReceived is TRUE");
						iForegroundObserver->SimulateKey();
						TRAPD(err1,ShowGlobalNoteL(false));
					}
				}
			}
		}
	}
	break;
	case EMsvEntriesMoved:
		{
			//LOGTXT("entries moved");
			TMsvId* entryId = static_cast<TMsvId*>(aArg2);
			if( *entryId == KMsvGlobalOutBoxIndexEntryId )
			{
				iMsgSendingAttempted = true;
				//LOGTXT("KMsvGlobalOutBoxIndexEntryId...");
			}
		}
		break;
	case EMsvEntriesDeleted:
		{
			//LOGTXT("entries deleted");
		}
		break;
	case EMsvCloseSession:
		iSession->RemoveObserver(*this);
		break;
	default:
		break;
	}
}

/**
 * This function simulates the RED key on the device
 * @return - NONE
 * */
void SMSMonitor::SendEvent()
{
	TWsEvent event;
	RWsSession wsSession = CCoeEnv::Static()->WsSession();
	TApaTaskList* taskList = new TApaTaskList((wsSession));
	TUid uid;
	uid.iUid = KUidGlobalNote;
	TApaTask task = taskList->FindApp(uid);
	if(task.Exists())
	{
		event.SetType(EEventKey);
		event.SetTimeNow();
		event.Key()->iCode = EKeyNo;
		event.Key()->iScanCode = EStdKeyNo;
		wsSession.SendEventToWindowGroup(task.WgId(),event);
		wsSession.Flush();
	}
}

/**
 * This function shows the global note displayed to the user on receipt of a message
 * @return - NONE
 * */
void SMSMonitor::ShowGlobalNoteL(bool aValue)
{
	//LOGTXT("ShowGlobalNoteL CALLED");
	delete iNote; 
	iNote = 0;
	iNote = CAknGlobalNote::NewL();
	iNote->CancelNoteL(0);
	delete iObserver;
	iObserver = 0;
	iObserver = new (ELeave) CGlobalObserver(CEikonEnv::Static());
	iNote->SetSoftkeys(R_AVKON_SOFTKEYS_SHOW_EXIT);
	iNote->SetGraphic(EMbmAvkonQgn_note_message, EMbmAvkonQgn_note_message_mask);
	iObserver->iStatus = KRequestPending;
	iObserver->Start();
	TBuf<100> tBuf;

	if(aValue) // Reboot
	{
		_LIT(KInformationText, "You have unread\nitem(s) in your Inbox.\nShow now?");
		tBuf.Zero();
		tBuf.Append(KInformationText);
		iNote->ShowNoteL(iObserver->iStatus, EAknGlobalTextNote, tBuf);
	}
	else // New message
	{
		LOGTXT("INSIDE NEW MESSAGE ELSE PART");
		if(iMsgReceived) // To avoid the note being displayed when the 'message delivery' notification arrived
		{
			LOGTXT("IMSGRECEIVED TRUE");
			_LIT(KInformationText, "Message received\nfrom\n");
			tBuf.Zero();
			tBuf.Append(KInformationText);
			tBuf.Append(iPhoneNumber);
			tBuf.Append(_L("\n\nPress 'C' to delete"));
			iNote->ShowNoteL(iObserver->iStatus, EAknGlobalTextNote, tBuf);
			iNoteDisplayed = true;
			iMsgReceived = false;
		}
		LOGTXT("IMSGRECEIVED FALSE");
	}
}

/**
 * This function indicates if the application's global note is displayed
 * @return - true if the note is displayed
 * */
bool SMSMonitor::IsNoteDisplayed()
{
	return iNoteDisplayed;
}

/**
 * This functions sets the value of the boolean which indicates if the global note is displayed
 * @return - NONE
 * */
void SMSMonitor::SetNoteDisplayed(bool aValue)
{
	iNoteDisplayed = aValue;
}

/**
 * This function opens the received message in the standard message viewer
 * @return - NONE
 * */
void SMSMonitor::OpenMsg()
{
	/** There is an own registry for UI MTM's */
	iMtmUiReg = CMtmUiRegistry::NewL( *iSession );

	CMsvEntry* serverEntry = iSession->GetEntryL( iMessageId );
	CleanupStack::PushL( serverEntry );

	/** Create new MTM */
	CBaseMtm* clientMtm = iMtmRegistry->NewMtmL( serverEntry->Entry().iMtm );

	CleanupStack::PushL( clientMtm );
	clientMtm->SwitchCurrentEntryL( serverEntry->EntryId() );

	CBaseMtmUi* ui = iMtmUiReg->NewMtmUiL( *clientMtm ); /** UI MTM for SMS */
	CleanupStack::PushL( ui );

	/** Display the SMS using the UI MTM. */
	iOperation = ui->ViewL( iStatus );
	CleanupStack::PopAndDestroy( 2 ); // ui, clientMtm, serverEntry
	SetActive();
}

/**
 * This function launches the messaging application
 * @return - NONE
 * */
void SMSMonitor::LaunchMessaging()
{
	TUid messagingUid;
	messagingUid.iUid = 0x100058c5;
	TThreadId threadId;
	RApaLsSession session;
	session.Connect();
	session.StartDocument(_L(""), messagingUid, threadId);
	session.Close();
	User::After(1000000);
	TInt scanCode = 63498;
	iForegroundObserver->SimulateKey(scanCode);
	scanCode = 63557;
	iForegroundObserver->SimulateKey(scanCode);
}

/**
 * This function is called by the platform upon completion of an asynchronous request
 * @return - NONE
 * */
void SMSMonitor::RunL()
{
	delete iOperation;
	iOperation = NULL;
}

/**
 * This function is called by the platform to cancel any asynchronous request
 * @return - NONE
 * */
void SMSMonitor::DoCancel()
{
	// Nothing to be done
}

/**
 * Just in case we need such a function in future that marks a message as "read"
 * @return - NONE
 * */
void SMSMonitor::MarkMsgAsRead()
{
	// There is an own registry for UI MTM's.
	iMtmUiReg = CMtmUiRegistry::NewL( *iSession );

	CMsvEntry* serverEntry = iSession->GetEntryL( iMessageId );
	CleanupStack::PushL( serverEntry );

	// Create new MTM.
	CBaseMtm* clientMtm = iMtmRegistry->NewMtmL( serverEntry->Entry().iMtm );// );

	CleanupStack::PushL( clientMtm );
	clientMtm->SwitchCurrentEntryL( serverEntry->EntryId() );

	TMsvEntry entry( serverEntry->Entry() );
	entry.SetNew( EFalse );         // message is no longer new
	entry.SetUnread( EFalse );      // message is no longer unread
	serverEntry->ChangeL( entry );  // commit changes
	CleanupStack::PopAndDestroy( 2 ); // clientMtm, serverEntry
}

/**
 * This functions deletes the received message
 * @return - NONE
 * */
void SMSMonitor::DeleteMessage()
{
	TMsvSelectionOrdering sort;
	sort.SetShowInvisibleEntries(ETrue);

	// Fetching entries currently in the inbox
	CMsvEntry* inboxContext = CMsvEntry::NewL(*iSession,KMsvGlobalInBoxIndexEntryId, sort);
	CleanupStack::PushL(inboxContext);

	CMsvEntrySelection* entries = inboxContext->ChildrenL();
	CleanupStack::PushL( entries );

	TInt index;
	bool entryFound = false;
	for(index=0; index<entries->Count(); index++)
	{
		TMsvId entryID = entries->At(index);
		if(entryID == iMessageId)
		{
			entryFound = true;
			CMsvEntry* serverEntry = iSession->GetEntryL(entries->At(index));
			serverEntry->DeleteL(serverEntry->EntryId());
		}
	}
	// The user deleted the SMS in the inbox, we need to re-send
	if(!entryFound) 
	{
		LOGTXT("ENTRY NOT FOUND");
	}

	CleanupStack::PopAndDestroy(entries);
	CleanupStack::PopAndDestroy(inboxContext);
}

/**
 * This functions checks if any unread item(s) are present in the device's Inbox
 * @return true if Unread item(s) are present, false otherwise
 * */
bool SMSMonitor::IsUnreadItem()
{
	TMsvSelectionOrdering sort;
	sort.SetShowInvisibleEntries(ETrue);

	// Fetching entries currently in the inbox
	CMsvEntry* inboxContext = CMsvEntry::NewL(*iSession,KMsvGlobalInBoxIndexEntryId, sort);
	CleanupStack::PushL(inboxContext);

	CMsvEntrySelection* entries = inboxContext->ChildrenL();
	CleanupStack::PushL( entries );

	TInt index;
	bool isUnread = false;
	for(index=0; index<entries->Count(); index++)
	{
		CMsvEntry* serverEntry = iSession->GetEntryL(entries->At(index));
		if(serverEntry->Entry().Unread())
		{
			iMessageId = serverEntry->EntryId();
			isUnread = true;
			break;
		}
	}

	CleanupStack::PopAndDestroy(entries);
	CleanupStack::PopAndDestroy(inboxContext);
	return isUnread;
}
